Jsx是一種語法的擴展(syntax extension),讓我們可以在Js裡面寫像是HTML的語法,這些像HTML的語法最終幫助我們產生HTML在畫面上。在React的概念裡,因為網頁應用的互動性越來越高(Js操作畫面HML),所以把Js和畫面寫在一起可以更方便維護,也可以讓彼此component隔離,減少那種改A壞B的問題發生。
在沒有使用Jsx之前會使用React提供的api來產出畫面,以下產出同樣的畫面兩種不同的寫法
// 使用JSX
const element = (
<div className="box">
<h1>哈囉 你好嗎?</h1>
<h2>真心感謝</h2>
</div>
)
// 使用 createElement
const H1El= React.createElement(
'h1',
{className: 'greeting'},
'哈囉 你好嗎?'
);
const H2El = React.createElement(
'h2',
null,
'真心感謝'
);
const BoxEl = React.createElement(
'div',
{className: 'box'},
[H1El,H2El]
);
才寫兩行字就要寫這麼多行,createElement是不是很麻煩,而且JSX看起來也跟之前在寫HTML比較像,比較起來親合多了,所以大多數還是會用JSX。
JSX會轉換為JS的物件,我們沒辦法讓funciton回傳超過一個物件,除非有陣列之類的包裹著,所以在這邊道理也是相同,需要在外層加上一個element。
// 正確 O
function App() {
return <div>
<h1>哈囉你好嗎</h1>
<h2>真心感謝</h2>
</div>
}
// 錯誤 X
function App() {
<h1>哈囉你好嗎</h1>
<h2>真心感謝</h2>
}
如果你不想外層包裹著一個無用的element,破壞原本HTML的結構,可以使用********來代替。
import { ****Fragment } from 'react'****
function App() {
return <****Fragment****>
<h1>哈囉你好嗎</h1>
<h2>真心感謝</h2>
</****Fragment****>
}
// 簡寫
function App() {
return <>
<h1>哈囉你好嗎</h1>
<h2>真心感謝</h2>
</>
}
可以用瀏覽器的檢查,查看兩者HTML的不同,使用Fragment沒有多餘的div
function App() {
return <h1>哈囉你好嗎</h1>
}
// 沒有結尾tag的就要自己關門,像是img、input
function App() {
return <>
<img src="abc.jpg" />
<input type="text" />
</>
}
function App() {
// class在JS是保留字,class要改成className,就跟JS的屬性相同
// data-*和aria-*比較像是特例沒有駝峰
return <img src="abc.jpg" className="photo" data-id="123" />
}
用{}包裹變數,可接在屬性正後面或標籤內容
function App() {
const person = {
name: '阿明',
age: 20,
img: 'abc.jpg'
}
return <>
<img src={person.img} />
<h1>{person.name}</h1>
<p>{person.age}</p>
<button>click</button>
</>
}
加入style,樣式以物件表示,也就是說外層的是JSX的大括號,裡面的式樣是物件,樣式也需要以駝峰命名
function App() {
return <>
<h1 style={{
backgroundColor: 'red'
}}>哈囉</h1>
</>
}
// 方法1
function App({name, isPass}) {
if (isPass) {
return <p>{name} O</p>
}
return <p>{name}</p>
}
// 方法2,3元運算,並可以用()包住多行
function App({name, isPass}) {
return <p>{isPass ?
name :
(<del>
name + 'O'
</del>)
}</p>
}
// 方法3,&&,如果前面是true就會回傳後面element
function App({name, isPass}) {
return <p>{name} {isPass && 'O'}</p>
}
//但,如果判斷是數字0就不適合用這種方式,react會回傳數字0,可以改用明確判斷>0、===0 或 <0代替
function App({name, count}) {
return <p>{count > 0 && name}</p>
}
// 方法4,把內容用變數存著
function App({name, isPass}) {
let content = name;
if (isPass) {
content = name + 'o'
}
return <p>{content}</p>
}
return 陣列可以渲染出多個element
可使用map或filter等JS的Array api來回傳陣列
const lyrics = [
{id: 1, text: '哈囉你好嗎'},
{id: 2, text: '真心感謝'},
{id: 3, text: '期待再相逢'},
]
function App() {
return <ul>
{
lyrics.map((lyrice) => {
return <li key={lyrice.id}>{lyrice.text}</li>
})
}
</ul>
}
使用List的方法必須在element加上一個獨一無二的key,做為每個item的識別。
注意事項
function App({name, isPass}) {
if (isPass) {
return null // 會回傳空白,undefined和false也有相同結果
}
return <p>{name}</p>
}
也是這次鐵人賽才去仔細翻了一下JSX文件,原來還有HTML轉JSX的工具可以用,還不熟練的可以上去玩玩看,快速幫助熟悉。
另外,也看到了文件的一段話,有人理解什麼意思嗎?不太理解這邊要表達的內容
React does not reset state when you go from rendering <><Child /></>
to [<Child />]
or back, or when you go from rendering <><Child /></>
to <Child />
and back. This only works a single level deep: for example, going from <><><Child /></></>
to <Child />
resets the state. See the precise semantics here.
https://transform.tools/html-to-jsx
https://react.dev/reference/react/Fragment
https://react.dev/learn/rendering-lists
https://react.dev/reference/react-dom/components/common
https://react.dev/learn/conditional-rendering